#ifndef TESTRUNNER_H
#define TESTRUNNER_H

#include <atlstr.h>
#include <atlpath.h>

#include "..\tdd.h"

namespace TddGui
{
struct Empty {};
template<typename B=Empty>
struct TestRunnerT : private B
{
	static TDD::Reporter& GetNullReporter()
	{
		struct NullReporter : public TDD::Reporter
		{
			virtual void ForEachTest(const TDD::UnitTestInfo&) {}
			virtual void ForEachFailure(const TDD::TestFailure&) {}
		};
		static NullReporter s_nr;
		return s_nr;
	}

	static HRESULT RunTddTestsInDll(const CString& csDll, TDD::Discriminator& pred, TDD::Reporter& func)
	{
		HRESULT hr = E_FAIL;
		HMODULE hinst = LoadLibrary(csDll);
		if (!hinst)
			hr = HRESULT_FROM_WIN32(GetLastError());
		else {
			void (__stdcall *fnRunTddTests)(TDD::Discriminator&, TDD::Reporter&);
			fnRunTddTests = (void (__stdcall *)(TDD::Discriminator&, TDD::Reporter&))GetProcAddress(hinst, "RunTddTests");
			if (!fnRunTddTests)
				hr = HRESULT_FROM_WIN32(GetLastError());
			else {
				hr = S_OK;
				fnRunTddTests(pred, func);
			}
			FreeLibrary(hinst);
		}
		return hr;
	}

	static HRESULT IsTestDll(const CPath& path)
	{
		class VerifierPredicate : public TDD::Discriminator
		{
			bool m_b;
		public:
			VerifierPredicate() : m_b(false) {}
			virtual bool WantTest(const TDD::UnitTestInfo& )
			{
				m_b = true;
				return false;
			}
			bool IsValid() const { return m_b; }
		};

		VerifierPredicate vp;
		HRESULT hr = RunTddTestsInDll(path, vp, GetNullReporter());
		if (FAILED(hr))
			return hr;
		if (vp.IsValid())
			return S_OK;
		return E_FAIL; // no tests found
	}
};
typedef TestRunnerT<> TestRunner;

}
#endif